﻿using System.Linq;

namespace Nomad.WebSync.Pocket.Sync {
    /// <summary>
    /// Synchorize data control for Pocket Outlook Contacts info
    /// </summary>
    class Contacts : SynchronizationControl {
        /// <summary>
        /// Creates a new instance of Contacts class
        /// </summary>
        public Contacts() : base() { }

        /// <summary>
        /// Synchronization starts process
        /// </summary>
        public override void Start() {
            // Get a list from contacts on server
            var remoteList = this.Service.GetContacts();
            // Search for new local contacts
            var localList = this.Session.GetDefaultFolder(PocketOutlook.OlDefaultFolders.olFolderContacts);
            // Get total of contacts to sync
            var count = remoteList.Count() + localList.Items.Count;
            // Index of current contact synchronization
            var index = 1;

            foreach (var remote in remoteList) {
                // Raises the progress event
                this.DoProgressChanged(index++, count);

                // Contacts that was inserted on server
                if (remote.State == (byte)States.InsertOnMobile) {
                    this.insertLocal(remote);
                    continue;
                }

                // Contacts that was updated on server
                if (remote.State == (byte)States.UpdateOnMobile) {
                    this.updateLocal(remote);
                    continue;
                }

                // Contacts thas was removed from server
                if (remote.State == (byte)States.RemoveFromMobile) {
                    this.removeLocal(remote);
                    continue;
                }

                // Search from local changes
                var local = this.getLocal(remote.oid);
                if (local == null) {
                    // Contact was removed from mobile, remove from server
                    this.removeRemote(remote);
                    continue;
                }

                // Test with contact has changes
                if (local.IsChanged(remote)) {
                    // Update remote contact
                    this.updateRemote(local, remote);
                    continue;
                }
            }

            foreach (var item in localList.Items) {
                // Raises the progress event
                this.DoProgressChanged(index++, count);

                // Get a instance for local intem
                var local = (PocketOutlook.IContact)item;

                // Verify if the contact is in server
                var remote = remoteList.SingleOrDefault(query => query.oid == local.oid);
                if (remote == null)
                    // New contact, insert on server
                    this.insertRemote(local);
            }
        }

        /// <summary>
        /// Search for a mobile contacts by your Outlook ID
        /// </summary>
        /// <param name="oid">Outlook ID of Contact</param>
        /// <returns>A PocketOutlook.IContact with found contact ou null</returns>
        private PocketOutlook.IContact getLocal(int oid) {
            try {
                return (PocketOutlook.IContact)this.Session.GetItemFromOid(oid);
            } catch {
                return null;
            }
        }
        /// <summary>
        /// Creates a new contact from mobile
        /// </summary>
        /// <returns>A PocketOutlook.IContact created</returns>
        private PocketOutlook.IContact createNew() {
            return (PocketOutlook.IContact)this.Session.CreateItem((int)PocketOutlook.OlItemType.olContactItem);
        }

        /// <summary>
        /// Insert a service contact info on Pocket Outlook session
        /// </summary>
        /// <param name="remoteContact">Service contact info</param>
        private void insertLocal(WebSyncService.Contact remote) {
            // Create the new contact
            var local = this.createNew();
            // Set propeties values from service contact
            local.FromService(remote);
            // Save new record
            local.Save();

            // Update remote info with new generetade oid
            remote.oid = local.oid;
            // Synchronize data on service
            this.Service.UpdateContact(remote);
        }
        /// <summary>
        /// Update a service contact info on Pocket Outlook session
        /// </summary>
        /// <param name="remoteContact">Service contact info</param>
        private void updateLocal(WebSyncService.Contact remote) {
            // Get mobile contact from current oid
            var local = this.getLocal(remote.oid);
            if (local == null) {
                // With not found contact insert a new one
                this.insertLocal(remote);
            } else {
                // Set propeties values from service contact
                local.FromService(remote);
                // Save changes
                local.Save();

                // Synchronize data on service
                this.Service.UpdateContact(remote);
            }
        }
        /// <summary>
        /// Remove a service contact from the Pocket Outlook session
        /// </summary>
        /// <param name="remoteContact">Service contact info</param>
        private void removeLocal(WebSyncService.Contact remote) {
            // Get mobile contact from current oid
            var local = this.getLocal(remote.oid);
            // If already deleted do nothing here
            if (local != null) local.Delete();
            // Remove contact from server
            this.Service.RemoveContact(remote);
        }

        /// <summary>
        /// Insert a new mobile contact on server
        /// </summary>
        /// <param name="localContact">Mobile contact info</param>
        private void insertRemote(PocketOutlook.IContact local) {
            // Sends the new contact to server
            this.updateRemote(local, new WebSyncService.Contact());
        }
        /// <summary>
        /// Update a mobile contact on server
        /// </summary>
        /// <param name="localContact">Mobile contact info</param>
        /// <param name="remoteContact">Service contact info</param>
        private void updateRemote(PocketOutlook.IContact local, WebSyncService.Contact remote) {
            // Get properties values from mobile contact
            remote.FromMobile(local);
            // Synchronize data on service
            this.Service.UpdateContact(remote);
        }
        /// <summary>
        /// Remove a contant from service
        /// </summary>
        /// <param name="remoteContact">Service contact info</param>
        private void removeRemote(WebSyncService.Contact remote) {
            this.Service.RemoveContact(remote);
        }        
    }

    /// <summary>
    /// Contacts data control extensions
    /// </summary>
    static class ContactsExtensions {
        /// <summary>
        /// Compare this PocketOutlook.IContact with a WebSyncService.Contact for properties diferences
        /// </summary>
        /// <param name="mobile">This PocketOutlook.IContact instance</param>
        /// <param name="service">WebSyncService.Contact reference instance</param>
        /// <returns>True with has some value diferente, False with all properties has the same value</returns>
        public static bool IsChanged(this PocketOutlook.IContact mobile, WebSyncService.Contact service) {
            // ATENCION:
            // The use of "System.Reflection" was throw a exception on execute the method GetValue 
            // of PropertyInfo from the interface PocketOutlook.IContact.
            // Using one by one setting value instead

            if (mobile.Anniversary != service.Anniversary) return true;
            if (mobile.AssistantName != service.AssistantName) return true;
            if (mobile.AssistantTelephoneNumber != service.AssistantTelephoneNumber) return true;
            if (mobile.Birthday != service.Birthday) return true;
            if (mobile.Body != service.Body) return true;
            if (mobile.Business2TelephoneNumber != service.Business2TelephoneNumber) return true;
            if (mobile.BusinessAddressCity != service.BusinessAddressCity) return true;
            if (mobile.BusinessAddressCountry != service.BusinessAddressCountry) return true;
            if (mobile.BusinessAddressPostalCode != service.BusinessAddressPostalCode) return true;
            if (mobile.BusinessAddressState != service.BusinessAddressState) return true;
            if (mobile.BusinessAddressStreet != service.BusinessAddressStreet) return true;
            if (mobile.BusinessFaxNumber != service.BusinessFaxNumber) return true;
            if (mobile.BusinessTelephoneNumber != service.BusinessTelephoneNumber) return true;
            if (mobile.CarTelephoneNumber != service.CarTelephoneNumber) return true;
            if (mobile.Categories != service.Categories) return true;
            if (mobile.Children != service.Children) return true;
            if (mobile.CompanyName != service.CompanyName) return true;
            if (mobile.Department != service.Department) return true;
            if (mobile.Email1Address != service.Email1Address) return true;
            if (mobile.Email2Address != service.Email2Address) return true;
            if (mobile.Email3Address != service.Email3Address) return true;
            if (mobile.FileAs != service.FileAs) return true;
            if (mobile.FirstName != service.FirstName) return true;
            if (mobile.Home2TelephoneNumber != service.Home2TelephoneNumber) return true;
            if (mobile.HomeAddressCity != service.HomeAddressCity) return true;
            if (mobile.HomeAddressCountry != service.HomeAddressCountry) return true;
            if (mobile.HomeAddressPostalCode != service.HomeAddressPostalCode) return true;
            if (mobile.HomeAddressState != service.HomeAddressState) return true;
            if (mobile.HomeAddressStreet != service.HomeAddressStreet) return true;
            if (mobile.HomeFaxNumber != service.HomeFaxNumber) return true;
            if (mobile.HomeTelephoneNumber != service.HomeTelephoneNumber) return true;
            if (mobile.JobTitle != service.JobTitle) return true;
            if (mobile.LastName != service.LastName) return true;
            if (mobile.MiddleName != service.MiddleName) return true;
            if (mobile.MobileTelephoneNumber != service.MobileTelephoneNumber) return true;
            if (mobile.OfficeLocation != service.OfficeLocation) return true;
            if (mobile.oid != service.oid) return true;
            if (mobile.OtherAddressCity != service.OtherAddressCity) return true;
            if (mobile.OtherAddressCountry != service.OtherAddressCountry) return true;
            if (mobile.OtherAddressPostalCode != service.OtherAddressPostalCode) return true;
            if (mobile.OtherAddressState != service.OtherAddressState) return true;
            if (mobile.OtherAddressStreet != service.OtherAddressStreet) return true;
            if (mobile.PagerNumber != service.PagerNumber) return true;
            if (mobile.RadioTelephoneNumber != service.RadioTelephoneNumber) return true;
            if (mobile.Spouse != service.Spouse) return true;
            if (mobile.Suffix != service.Suffix) return true;
            if (mobile.Title != service.Title) return true;
            if (mobile.WebPage != service.WebPage) return true;

            return false;
        }

        /// <summary>
        /// Copy all propeties values from a WebSyncService.Contact in this PocketOutlook.IContact
        /// </summary>
        /// <param name="mobile">This PocketOutlook.IContact</param>
        /// <param name="service">WebSyncService.Contact source</param>
        public static void FromService(this PocketOutlook.IContact mobile, WebSyncService.Contact service) {
            // ATENCION:
            // The use of "System.Reflection" was throw a exception on execute the method GetValue 
            // of PropertyInfo from the interface PocketOutlook.IContact.
            // Using one by one setting value instead            

            mobile.Anniversary = service.Anniversary;
            mobile.AssistantName = service.AssistantName;
            mobile.AssistantTelephoneNumber = service.AssistantTelephoneNumber;
            mobile.Birthday = service.Birthday;
            mobile.Body = service.Body;
            mobile.Business2TelephoneNumber = service.Business2TelephoneNumber;
            mobile.BusinessAddressCity = service.BusinessAddressCity;
            mobile.BusinessAddressCountry = service.BusinessAddressCountry;
            mobile.BusinessAddressPostalCode = service.BusinessAddressPostalCode;
            mobile.BusinessAddressState = service.BusinessAddressState;
            mobile.BusinessAddressStreet = service.BusinessAddressStreet;
            mobile.BusinessFaxNumber = service.BusinessFaxNumber;
            mobile.BusinessTelephoneNumber = service.BusinessTelephoneNumber;
            mobile.CarTelephoneNumber = service.CarTelephoneNumber;
            mobile.Categories = service.Categories;
            mobile.Children = service.Children;
            mobile.CompanyName = service.CompanyName;
            mobile.Department = service.Department;
            mobile.Email1Address = service.Email1Address;
            mobile.Email2Address = service.Email2Address;
            mobile.Email3Address = service.Email3Address;
            mobile.FileAs = service.FileAs;
            mobile.FirstName = service.FirstName;
            mobile.Home2TelephoneNumber = service.Home2TelephoneNumber;
            mobile.HomeAddressCity = service.HomeAddressCity;
            mobile.HomeAddressCountry = service.HomeAddressCountry;
            mobile.HomeAddressPostalCode = service.HomeAddressPostalCode;
            mobile.HomeAddressState = service.HomeAddressState;
            mobile.HomeAddressStreet = service.HomeAddressStreet;
            mobile.HomeFaxNumber = service.HomeFaxNumber;
            mobile.HomeTelephoneNumber = service.HomeTelephoneNumber;
            mobile.JobTitle = service.JobTitle;
            mobile.LastName = service.LastName;
            mobile.MiddleName = service.MiddleName;
            mobile.MobileTelephoneNumber = service.MobileTelephoneNumber;
            mobile.OfficeLocation = service.OfficeLocation;
            mobile.OtherAddressCity = service.OtherAddressCity;
            mobile.OtherAddressCountry = service.OtherAddressCountry;
            mobile.OtherAddressPostalCode = service.OtherAddressPostalCode;
            mobile.OtherAddressState = service.OtherAddressState;
            mobile.OtherAddressStreet = service.OtherAddressStreet;
            mobile.PagerNumber = service.PagerNumber;
            mobile.RadioTelephoneNumber = service.RadioTelephoneNumber;
            mobile.Spouse = service.Spouse;
            mobile.Suffix = service.Suffix;
            mobile.Title = service.Title;
            mobile.WebPage = service.WebPage;
        }

        /// <summary>
        /// Copy all propeties values from a PocketOutlook.IContact in this WebSyncService.Contact
        /// </summary>
        /// <param name="service">This WebSyncService.Contact</param>
        /// <param name="mobile">PocketOutlook.IContact source</param>
        public static void FromMobile(this WebSyncService.Contact service, PocketOutlook.IContact mobile) {
            // ATENCION:
            // The use of "System.Reflection" was throw a exception on execute the method GetValue 
            // of PropertyInfo from the interface PocketOutlook.IContact.
            // Using one by one setting value instead            

            service.oid = mobile.oid;
            service.Anniversary = mobile.Anniversary;
            service.AssistantName = mobile.AssistantName;
            service.AssistantTelephoneNumber = mobile.AssistantTelephoneNumber;
            service.Birthday = mobile.Birthday;
            service.Body = mobile.Body;
            service.Business2TelephoneNumber = mobile.Business2TelephoneNumber;
            service.BusinessAddressCity = mobile.BusinessAddressCity;
            service.BusinessAddressCountry = mobile.BusinessAddressCountry;
            service.BusinessAddressPostalCode = mobile.BusinessAddressPostalCode;
            service.BusinessAddressState = mobile.BusinessAddressState;
            service.BusinessAddressStreet = mobile.BusinessAddressStreet;
            service.BusinessFaxNumber = mobile.BusinessFaxNumber;
            service.BusinessTelephoneNumber = mobile.BusinessTelephoneNumber;
            service.CarTelephoneNumber = mobile.CarTelephoneNumber;
            service.Categories = mobile.Categories;
            service.Children = mobile.Children;
            service.CompanyName = mobile.CompanyName;
            service.Department = mobile.Department;
            service.Email1Address = mobile.Email1Address;
            service.Email2Address = mobile.Email2Address;
            service.Email3Address = mobile.Email3Address;
            service.FileAs = mobile.FileAs;
            service.FirstName = mobile.FirstName;
            service.Home2TelephoneNumber = mobile.Home2TelephoneNumber;
            service.HomeAddressCity = mobile.HomeAddressCity;
            service.HomeAddressCountry = mobile.HomeAddressCountry;
            service.HomeAddressPostalCode = mobile.HomeAddressPostalCode;
            service.HomeAddressState = mobile.HomeAddressState;
            service.HomeAddressStreet = mobile.HomeAddressStreet;
            service.HomeFaxNumber = mobile.HomeFaxNumber;
            service.HomeTelephoneNumber = mobile.HomeTelephoneNumber;
            service.JobTitle = mobile.JobTitle;
            service.LastName = mobile.LastName;
            service.MiddleName = mobile.MiddleName;
            service.MobileTelephoneNumber = mobile.MobileTelephoneNumber;
            service.OfficeLocation = mobile.OfficeLocation;
            service.OtherAddressCity = mobile.OtherAddressCity;
            service.OtherAddressCountry = mobile.OtherAddressCountry;
            service.OtherAddressPostalCode = mobile.OtherAddressPostalCode;
            service.OtherAddressState = mobile.OtherAddressState;
            service.OtherAddressStreet = mobile.OtherAddressStreet;
            service.PagerNumber = mobile.PagerNumber;
            service.RadioTelephoneNumber = mobile.RadioTelephoneNumber;
            service.Spouse = mobile.Spouse;
            service.Suffix = mobile.Suffix;
            service.Title = mobile.Title;
            service.WebPage = mobile.WebPage;
        }
    }
}
